package vis.core.service.sys.impl;


import vis.core.common.cache.Cache;
import vis.core.common.cache.CacheKey;
import vis.core.common.security.AuthKit;
import vis.core.common.security.AuthUser;
import vis.core.common.util.IdKit;
import vis.core.common.util.ObjectKit;
import vis.core.common.util.StringKit;
import vis.core.domain.db.SysMenu;
import vis.core.mapper.SysMenuMapper;
import vis.core.mapper.SysOrgMenuMapper;
import vis.core.mapper.SysRoleMenuMapper;
import vis.core.service.sys.SysMenuService;
import vis.core.service.sys.SysResService;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.mybatisflex.core.query.QueryWrapper;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;


/**
 * 用户表实现
 */
@Slf4j
@Service
public class SysMenuServiceImpl implements SysMenuService {

    @Resource
    private Cache<String> cache;

    @Resource
    private SysRoleMenuMapper sysRoleMenuMapper;

    @Resource
    private SysOrgMenuMapper sysOrgMenuMapper;

    @Resource
    private SysMenuMapper sysMenuMapper;

    @Resource
    private SysRoleMenuMapper roleMenuMapper;

    @Autowired
    @Lazy
    private SysResService sysResService;

    @Override
    public boolean insert(SysMenu param) {
        param.setId(IdKit.getId());
        if (StringKit.isBlank(param.getPid())) param.setPid("0");

        //遍历树结构
        JSONArray ids = getTreeIds(param.getId(), param.getPid());
        param.setTreePath(ids.toString());

        int i = sysMenuMapper.insertSelective(param);

        //清缓存
        cache.delete(CacheKey.MENU_SYSTEM_ALL_DATA.key());

        return true;
    }

    @Override
    public boolean update(SysMenu param) {
        SysMenu sysMenu = ObjectKit.copyToNew(param, "id", "pid", "level", "name", "routePath", "param", "filePath", "type", "sort", "res", "resExclude");

        //遍历树结构
        JSONArray ids = getTreeIds(param.getId(), param.getPid());
        sysMenu.setTreePath(ids.toString());

        int i = sysMenuMapper.update(sysMenu);

        //清缓存
        cache.delete(CacheKey.MENU_SYSTEM_ALL_DATA.key());

        //查询所有和该菜单相关的角色，更新这些角色的权限
        refreshRoleMenuResCache(param.getId());

        return true;
    }

    //查询所有和该菜单相关的角色，
    //更新这些角色的权限
    private void refreshRoleMenuResCache(String menuId) {
        //查询该菜单的上下级
        QueryWrapper wrapper = new QueryWrapper();
        wrapper.select("tree_path").like("tree_path", '"' + menuId + '"');
        List<SysMenu> sysMenus = sysMenuMapper.selectListByQuery(wrapper);
        HashSet<Object> menuIds = new HashSet<>();
        for (SysMenu sysMenu : sysMenus) {
            menuIds.addAll(JSONArray.parseArray(sysMenu.getTreePath()));
        }

        //查询与这些菜单有关系的角色
        QueryWrapper roleMenuQuery = new QueryWrapper();
        roleMenuQuery.in("menu_id", menuIds);
        roleMenuQuery.select("role_id");
        HashSet<String> roleIds = new HashSet<>(roleMenuMapper.selectListByQueryAs(roleMenuQuery, String.class));

        //更新这些角色缓存
        sysResService.refreshRoleResCache(roleIds);
    }

    //删除菜单
    @Override
    public boolean delete(String ids) {
        ArrayList<String> split = StringKit.split(ids);

        int i = sysMenuMapper.deleteBatchByIds(split);

        //清缓存
        cache.delete(CacheKey.MENU_SYSTEM_ALL_DATA.key());

        return true;
    }

    //根据ID和PID查库，返回树结构JSON数组 ["PID-0","PID-01","自身ID"]
    @Override
    public JSONArray getTreeIds(String nowId, String pid) {
        JSONArray treeIds = new JSONArray();
        treeIds.add(nowId);
        if (!"0".equals(pid)) {
            do {
                QueryWrapper wrapper = new QueryWrapper();
                wrapper.select("id", "pid").from(SysMenu.class).where("id = ?", pid);
                SysMenu sysMenu = sysMenuMapper.selectOneByQuery(wrapper);
                if (sysMenu != null) {
                    pid = sysMenu.getPid();
                    treeIds.add(0, sysMenu.getId());
                }
            } while (pid != null && !pid.equals("0"));
        }
        return treeIds;
    }

    //系统中全部菜单
    @Override
    public List<SysMenu> allMenuCache() {
        //缓存中有菜单
        String sysMenuStr = cache.get(CacheKey.MENU_SYSTEM_ALL_DATA.key());

        if (StringKit.isNotBlank(sysMenuStr)) {
            List<SysMenu> menuAllList = JSONArray.parseArray(sysMenuStr, SysMenu.class);
            if (menuAllList.size() > 0) return menuAllList;
        }

        QueryWrapper wrapper = QueryWrapper.create().select("*").orderBy("sort", true).orderBy("ct", false);

        List<SysMenu> menuAllList = sysMenuMapper.selectListByQuery(wrapper);
        cache.set(CacheKey.MENU_SYSTEM_ALL_DATA.key(), JSONObject.toJSONString(menuAllList));
        return menuAllList;
    }

    //返回已登录用户具备的菜单
    public List<SysMenu> userHasMenu() {
        AuthUser currentUser = AuthKit.getCurrentUser();

        //全部菜单
        List<SysMenu> allMenuList = allMenuCache();

        //root直接返回所有菜单
        if (currentUser.getIsRoot()) return allMenuList;

        //用户具备的角色，角色具备的菜单ID
        List<String> roleIds = currentUser.getRoleIds();
        QueryWrapper roleMenuQuery = QueryWrapper.create().select("menu_id").in("role_id", roleIds);
        List<String> roleMenuIds = sysRoleMenuMapper.selectObjectListByQueryAs(roleMenuQuery, String.class);

        //用户所在部门，部门具备的菜单ID
        List<String> orgIds = currentUser.getOrgIds();
        List<String> orgMenuIds = new ArrayList<>();
        if (!orgIds.isEmpty()) {
            QueryWrapper orgMenuQuery = QueryWrapper.create().select("menu_id").in("org_id", orgIds);
            orgMenuIds = sysOrgMenuMapper.selectObjectListByQueryAs(orgMenuQuery, String.class);
        }

        //菜单ID去重汇总
        HashSet<String> allIds = new HashSet<>();
        allIds.addAll(roleMenuIds);
        allIds.addAll(orgMenuIds);

        //根据ID,查树内的集合数据，去重后返回
        return getTreePathData(allIds);
    }

    //根据菜单ID,查询包含自身的全路径数据，去重后返回（走缓存）
    @Override
    public List<SysMenu> getTreePathData(Collection<String> menuIds) {
        //从缓存中获取全部菜单
        List<SysMenu> allMenuData = allMenuCache();

        //遍历出查询ID数据
        List<SysMenu> sysMenus = allMenuData.stream().filter(e -> menuIds.contains(e.getId())).toList();

        //取出TreePath内ID,去重
        HashSet<String> allTreePathMenuIds = new HashSet<>();
        for (SysMenu sysMenu : sysMenus) {
            String treePath = sysMenu.getTreePath();
            if (StringKit.isNotBlank(treePath)) {
                allTreePathMenuIds.addAll(JSONArray.parseArray(treePath).toJavaList(String.class));
            }
        }

        //筛选出数据，返回
        return allMenuData.stream().filter(e -> allTreePathMenuIds.contains(e.getId())).toList();
    }

    // 根据菜单ID 集合，获取查询包含自身的全路径数据，具备的资源，去重后返回（走缓存）
    @Override
    public HashSet<String> getTreePathMenuHasRes(Collection<String> menuIds) {
        //根据ID,查树内的集合数据，去重后返回
        List<SysMenu> treePathMenu = getTreePathData(menuIds);

        //汇总全部具备资源
        HashSet<String> allHasRes = new HashSet<>();
        HashSet<String> allExcludeRes = new HashSet<>();
        for (SysMenu sysMenu : treePathMenu) {
            if (sysMenu != null) {
                allHasRes.addAll(StringKit.split(sysMenu.getRes()));
                allExcludeRes.addAll(StringKit.split(sysMenu.getResExclude()));
            }
        }

        return StringKit.pathMatcherHasData(allHasRes, allExcludeRes);
    }

    //给该角色，添加此菜单的权限
//    private void addRoleMenu(List<String> roleIds, String menuId) {
//        for (String roleId : roleIds) {
//            SysRoleMenu lkRoleMenu = new SysRoleMenu();
//            lkRoleMenu.setRoleId(roleId);
//            lkRoleMenu.setMenuId(menuId);
//            try {
//                sysRoleMenuMapper.insertSelectiveWithPk(lkRoleMenu);
//            } catch (Exception e) {
//                e.printStackTrace();
//            }
//        }
//    }

}
